package pers.chao.tool.thread.pool.impl;

import pers.chao.tool.thread.pool.IExecutor;

import java.util.List;
import java.util.concurrent.*;

/**
 * Description: 多种定制好的线程池，适用各种场景
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newExceedWaitPool	              在满足通用规则的前提下，当任务数大于maximumPoolSize，溢出的任务会在溢出等待队列中等待，
 *                                    直到有任务执行完成，线程空闲出来再进行执行，溢出等待队列符合Fifo进出队列规则
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newExceedDiscardPool	               在满足通用规则的前提下，当任务数大于maximumPoolSize，溢出的任务会直接被丢弃
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newExceedCallerRunsPool	           在满足通用规则的前提下，当任务数大于maximumPoolSize，溢出的任务在调用线程执行方
 *                                     法(execute/submit)所在线程直接执行
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newExceedCallImmediatelyPool	    在满足通用规则的前提下，当任务数大于maximumPoolSize，溢出的任务在全局缓存线程池中直接执行
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newSinglePool	                   规则与java.util.concurrent.Executors#newSingleThreadExecutor()相同
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newFixedPool	                       规则与java.util.concurrent.Executors#newFixedThreadPool(int)相同
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newCachedPool	                   规则与java.util.concurrent.Executors#newCachedThreadPool()相同
 * ----------------------------  |  ---------------------------------------------------------------------------------
 * newNoCorePool	                  如果有threadCount个数的任务正在运行，再增加进来的任务将会进入等待队列中直到有线程空闲出来。
 *                                    如果空闲线程空闲的时间大于keepAliveTime，那么它将会被回收
 * ----------------------------  |  ---------------------------------------------------------------------------------
 *
 * @author W.Chao
 * @date 2020/12/13 22:54
 **/
public class RealExecutors {
	// 临时线程池
	private static final IExecutor TEMPORARY_CACHED_THREAD_POOL = ProposedThreadPool.
			newCachedPool(5L, TimeUnit.SECONDS, "TemporaryCachedThreadPool");

	/**
	 * 核心线程数和最大线程数相同
	 */
	public static class NoCoreExecutor extends RealExecutor {
		public NoCoreExecutor(int threadCount, long keepAliveTime, TimeUnit unit,
							  String prefixName) {
			super(threadCount, threadCount, keepAliveTime, unit,
					new LinkedBlockingQueue<>(),
					new AbortPolicy(), // 丢弃策略，抛出异常
					prefixName);

			// 核心线程超时也会被回收
			allowCoreThreadTimeOut(true);
		}
	}

	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 当前任务入队列，直到有闲置线程可执行任务
	 */
	public static class ExceedWaitExecutor extends RealExecutor {

		public ExceedWaitExecutor(int corePoolSize,
								  int maximumPoolSize, long keepAliveTime, TimeUnit unit, String prefixName,
								  ExceedWait.Queue queue, ExceedWait.RejectedHandler rejectedHandler) {
			super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
					queue, rejectedHandler, prefixName);
		}

		public ExceedWaitExecutor(int corePoolSize,
								  int maximumPoolSize, long keepAliveTime, TimeUnit unit, String prefixName) {
			this(corePoolSize, maximumPoolSize, keepAliveTime, unit, prefixName,
					new ExceedWait.Queue(), new ExceedWait.RejectedHandler());
		}

		@Override
		public List<Runnable> shutdownNow() {
			List<Runnable> tasks = super.shutdownNow();
			tasks.addAll(((ExceedWait.Queue) getQueue()).drainExceedQueue());
			return tasks;
		}

		@Override
		public long getTaskCount() {
			return super.getTaskCount() + ((ExceedWait.Queue) getQueue()).exceedSize();
		}
	}

	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 当前任务被丢弃
	 */
	static class ExceedDiscardExecutor extends RealExecutor {
		public ExceedDiscardExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
									 TimeUnit unit, String prefixName) {
			super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
					new SynchronousQueue<>(true),
					new DiscardPolicy(), prefixName); // 丢弃策略，不抛出异常
		}
	}

	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 将使用当前的调用线程执行任务
	 */
	static class ExceedCallerRunsExecutor extends RealExecutor {
		public ExceedCallerRunsExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
										TimeUnit unit, String prefixName) {
			super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
					new SynchronousQueue<>(true),
					new CallerRunsPolicy(), prefixName); // 重试策略
		}
	}

	/**
	 * 超出核心线程数的任务将新建线程执行并至最大线程数，最大线程数量都在执行时，
	 * 将使用临时线程池执行任务
	 * corePoolSize: 线程池保存的活动最小线程数
	 */
	static class ExceedCallImmediatelyExecutor extends RealExecutor {
		public ExceedCallImmediatelyExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
											 TimeUnit unit, String prefixName) {

			super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
					new SynchronousQueue<>(true),
					(runnable, executor) -> {
						if (!executor.isShutdown()) {
							TEMPORARY_CACHED_THREAD_POOL.
									execute(((RealExecutor) executor).getTaskNameMap().get(runnable),
											runnable);
						}
					}, prefixName);
		}
	}

	/**
	 * 单线程线程池
	 */
	static class SinglePoolExecutor extends RealExecutor {
		public SinglePoolExecutor(String prefixName) {
			super(1, 1, 0L, TimeUnit.MILLISECONDS,
					new LinkedBlockingQueue<>(), // 无界队列
					new AbortPolicy(), // 丢弃策略，抛出异常
					prefixName);
		}
	}

	/**
	 * 固定线程数量线程池
	 */
	static class FixedPoolExecutor extends RealExecutor {
		public FixedPoolExecutor(int threadCount, String prefixName) {
			super(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS,
					new LinkedBlockingQueue<>(), // 无界队列
					new AbortPolicy(), // 丢弃策略，抛出异常
					prefixName);
		}
	}

	/**
	 * 无最大线程数量限制，超出核心线程数时，超出的线程数闲置时，超出keepAliveTime时间将会被回收
	 */
	static class CachedPoolExecutor extends RealExecutor {
		public CachedPoolExecutor(long keepAliveTime, TimeUnit unit, String prefixName) {
			super(0, Integer.MAX_VALUE, keepAliveTime, unit, new SynchronousQueue<>(true),
					new AbortPolicy(), // 丢弃策略，抛出异常
					prefixName);
		}
	}

}
